package com.gc.materialdesign.views;

import com.gc.materialdesign.ResourceTable;
import com.gc.materialdesign.utils.ImageUtil;
import com.gc.materialdesign.utils.ResUtil;
import com.gc.materialdesign.utils.ShapeUtil;
import com.gc.materialdesign.utils.Utils;

import ohos.agp.components.*;
import ohos.agp.components.element.Element;
import ohos.agp.components.element.ElementScatter;
import ohos.agp.components.element.ShapeElement;
import ohos.agp.render.Canvas;
import ohos.agp.render.Paint;
import ohos.agp.render.PixelMapHolder;
import ohos.agp.utils.Color;
import ohos.agp.utils.LayoutAlignment;
import ohos.agp.utils.RectFloat;
import ohos.app.Context;
import ohos.media.image.PixelMap;
import ohos.multimodalinput.event.MmiPoint;
import ohos.multimodalinput.event.TouchEvent;

public class CheckBox extends CustomView implements Component.TouchEventListener {
    private String backgroundColor = "#4CAF50FF";

    private Check checkView;

    private boolean press = false;
    private boolean check = false;

    private OnCheckListener onCheckListener;

    public CheckBox(Context context) {
        this(context, null);
    }

    public CheckBox(Context context, AttrSet attrs) {
        this(context, attrs, null);
    }

    public CheckBox(Context context, AttrSet attrs, String defStyleAttr) {
        super(context, attrs, defStyleAttr);
        setAttributes(context, attrs);
        setTouchEventListener(this);
    }

    // Set atributtes of XML to View
    protected void setAttributes(Context context, AttrSet attrs) {
        Element element = ElementScatter.getInstance(context).parse(ResourceTable.Graphic_background_checkbox);
        setBackground(element);

        // Set size of view
        setMinHeight(Utils.dpToPx(48, context));
        setMinWidth(Utils.dpToPx(48, context));

        // Set background Color
        // Color by resource
        boolean backgroundIsPresent = attrs.getAttr("background").isPresent();
        if (backgroundIsPresent) {
            String color = attrs.getAttr("background").get().getStringValue();
            setBackgroundColor(color);
            setBackground(ShapeUtil.createCircleDrawable(Color.getIntColor(Utils.rgba(color))));
        }

        boolean checkIsPresent = attrs.getAttr("check").isPresent();
        if (checkIsPresent) {
            boolean check = attrs.getAttr("check").get().getBoolValue();
            this.check = check;
        }

        getComponentTreeObserver().addWindowBoundListener(new ComponentTreeObserver.WindowBoundListener() {
            @Override
            public void onWindowBound() {
                setChecked(check);
                setPressState(false);
                ShapeElement shapeElement =
                        ShapeUtil.createCircleDrawable(ResUtil.getColor(context, ResourceTable.Color_transparent));
                setBackground(shapeElement);
            }

            @Override
            public void onWindowUnbound() {

            }
        });

        DirectionalLayout directionalLayout = new DirectionalLayout(context);
        DirectionalLayout.LayoutConfig config =
                new DirectionalLayout.LayoutConfig(LayoutConfig.MATCH_CONTENT, LayoutConfig.MATCH_CONTENT);
        directionalLayout.setOrientation(Component.HORIZONTAL);
        directionalLayout.setAlignment(LayoutAlignment.VERTICAL_CENTER);
        directionalLayout.setLayoutConfig(config);

        checkView = new Check(context);
        DirectionalLayout.LayoutConfig layoutConfig =
                new DirectionalLayout.LayoutConfig(Utils.dpToPx(20, context), Utils.dpToPx(20, context));
        checkView.setLayoutConfig(layoutConfig);
        directionalLayout.addComponent(checkView);

        // Adding text view to checkbox
        boolean textIsPresent = attrs.getAttr("text").isPresent();
        String text = null;
        if (textIsPresent) {
            text = attrs.getAttr("text").get().getStringValue();
        }

        if (text != null) {
            Text textView = new Text(context);
            DirectionalLayout.LayoutConfig textLayoutConfig =
                    new DirectionalLayout.LayoutConfig(LayoutConfig.MATCH_CONTENT, LayoutConfig.MATCH_CONTENT);
            textLayoutConfig.setMargins(10, 0, 0, 0);
            textView.setLayoutConfig(textLayoutConfig);
            textView.setText(text);
            textView.setTextSize(12, Text.TextSizeType.FP);

            directionalLayout.addComponent(textView);
        }
        addComponent(directionalLayout);
    }

    @Override
    public void invalidate() {
        checkView.invalidate();
        super.invalidate();
    }

    @Override
    public boolean onTouchEvent(Component component, TouchEvent event) {
        invalidate();
        int action = event.getAction();
        MmiPoint mmiPoint = event.getPointerScreenPosition(event.getIndex());
        if (isEnabled()) {
            isLastTouch = true;
            if (action == TouchEvent.PRIMARY_POINT_DOWN) {
                setBackground(
                        ShapeUtil.createCircleDrawable(
                                Color.getIntColor(check ? makePressColorString(true) : "#6D6D6D44")));
            } else if (action == TouchEvent.PRIMARY_POINT_UP) {
                setBackground(
                        ShapeUtil.createCircleDrawable(
                                ResUtil.getColor(getContext(), ResourceTable.Color_transparent)));
                press = false;
                float x = Math.abs(mmiPoint.getX() - getLocationOnScreen()[0]);
                float y = Math.abs(mmiPoint.getY() - getLocationOnScreen()[1]);
                if (x <= getWidth() && y <= getHeight()) {
                    isLastTouch = false;
                    check = !check;
                    if (onCheckListener != null) {
                        onCheckListener.onCheck(CheckBox.this, check);
                    }
                    if (check) {
                        step = 0;
                        checkView.changeBackground();
                    }
                }
            }
        }

        return true;
    }

    @Override
    public void onDraw(Component component, Canvas canvas) {
        super.onDraw(component, canvas);
        if (press) {
            Paint paint = new Paint();
            paint.setAntiAlias(true);
            paint.setColor(new Color(Color.getIntColor(check ? Utils.argb(makePressColorString(false)) : "#446D6D6D")));
            canvas.drawCircle(getWidth() / 2, getHeight() / 2, getWidth() / 2, paint);
            getContext().getUITaskDispatcher().asyncDispatch(this::invalidate);
        }
    }

    /**
     * 改变颜色值
     * @param isRGBA 是否为rgba模式
     * @return 改变后的颜色值
     */
    protected String makePressColorString(boolean isRGBA) {
        int colorInt;
        if (backgroundColor.length() == 7) {
            colorInt = Color.getIntColor(backgroundColor);
        } else {
            colorInt = Color.getIntColor(backgroundColor.substring(0, backgroundColor.length() - 2));
        }
        int r = (colorInt >> 16) & 0xFF;
        int g = (colorInt >> 8) & 0xFF;
        int b = (colorInt >> 0) & 0xFF;
        r = Math.max(r - 30, 0);
        g = Math.max(g - 30, 0);
        b = Math.max(b - 30, 0);
        StringBuilder builder;
        if (isRGBA) {
            builder =
                    new StringBuilder("#")
                            .append(colorPrefix(Integer.toHexString(r)))
                            .append(colorPrefix(Integer.toHexString(g)))
                            .append(colorPrefix(Integer.toHexString(b)))
                            .append(Integer.toHexString(30));
        } else {
            builder =
                    new StringBuilder("#")
                            .append(Integer.toHexString(30))
                            .append(colorPrefix(Integer.toHexString(r)))
                            .append(colorPrefix(Integer.toHexString(g)))
                            .append(colorPrefix(Integer.toHexString(b)));
        }
        return builder.toString();
    }

    private String colorPrefix(String string) {
        return string.length() > 1 ? string : "00";
    }

    public void setBackgroundColor(String colorStr) {
        backgroundColor = colorStr;
        if (isEnabled()) {
            beforeBackground = backgroundColor;
        }
    }

    public void setChecked(boolean check) {
        invalidate();
        this.check = check;
        setPressState(false);
        setBackground(ShapeUtil.createCircleDrawable(ResUtil.getColor(getContext(), ResourceTable.Color_transparent)));
        if (check) {
            step = 0;
            checkView.changeBackground();
        }
    }

    public boolean isCheck() {
        return check;
    }

    // Indicate step in check animation
    private int step = 0;

    // View that contains checkbox
    class Check extends Component implements DrawTask {
        PixelMap sprite;
        Paint paint;

        public Check(Context context) {
            super(context);
            Element element =
                    ElementScatter.getInstance(context).parse(ResourceTable.Graphic_background_checkbox_uncheck);
            setBackground(element);
            sprite = ImageUtil.decodeSampledBitmapFromResource(context, ResourceTable.Media_sprite_check);
            paint = new Paint();
            paint.setAntiAlias(true);
            addDrawTask(this);
        }

        public void changeBackground() {
            if (check) {
                ShapeElement element =
                        ShapeUtil.createDrawable(
                                Color.getIntColor(Utils.rgba(backgroundColor)), Utils.dpToPx(2, getContext()));
                setBackground(element);
            } else {
                Element element =
                        ElementScatter.getInstance(getContext())
                                .parse(ResourceTable.Graphic_background_checkbox_uncheck);
                setBackground(element);
            }
        }

        @Override
        public void onDraw(Component component, Canvas canvas) {
            if (check) {
                if (step < 11) {
                    step++;
                    // 直接调用invalidate无效
                    getContext().getUITaskDispatcher().asyncDispatch(() -> invalidate());
                }
            } else {
                if (step >= 0) {
                    step--;
                    getContext().getUITaskDispatcher().asyncDispatch(() -> invalidate());
                }
                if (step == -1) {
                    getContext().getUITaskDispatcher().asyncDispatch(() -> invalidate());
                    changeBackground();
                }
            }

            RectFloat src = new RectFloat(40 * step, 0, (40 * step) + 40, 40);
            RectFloat dst = new RectFloat(0, 0, this.getWidth() - 2, this.getHeight());
            canvas.drawPixelMapHolderRect(new PixelMapHolder(sprite), src, dst, paint);
        }
    }

    public void setOnCheckListener(OnCheckListener onCheckListener) {
        this.onCheckListener = onCheckListener;
    }

    public interface OnCheckListener {
        void onCheck(CheckBox view, boolean check);
    }
}
